package com.flux.dispatcher

import android.support.v4.util.ArrayMap

import com.flux.action.RxAction
import com.flux.action.RxStoreChange

import io.reactivex.disposables.Disposable

/**
 * Created by marcel on 13/08/15.
 * RxFlux dispatcher, contains the the registered actions, stores and the instance of the RxBus
 * responsible to send events to the stores. This class is used as a singleton.
 */
object Dispatcher {

    fun init(bus: RxBus) {
        this.bus = bus
    }

    private lateinit var bus: RxBus
    private val rxActionMap: ArrayMap<String, Disposable> = ArrayMap()
    private val rxStoreMap: ArrayMap<String, Disposable> = ArrayMap()

    fun <T : RxActionDispatch> subscribeRxStore(`object`: T) {
        val tag = `object`.tag
        val disposable = rxActionMap[tag]
        if (disposable == null || disposable.isDisposed) {
            rxActionMap.put(tag, bus.get().filter { o -> o is RxAction }
                    .subscribe { o -> `object`.onRxAction(o as RxAction) })
        }
    }

    fun <T : RxViewDispatch> subscribeRxView(`object`: T) {
        val tag = `object`.getRxTag()
        val disposable = rxStoreMap[tag]
        if (disposable == null || disposable.isDisposed) {
            rxStoreMap.put(tag, bus.get().filter { o -> o is RxStoreChange }
                    .subscribe { o -> `object`.onRxStoreChanged(o as RxStoreChange) })
        }
    }

    fun <T : RxActionDispatch> unsubscribeRxStore(`object`: T) {
        val tag = `object`.tag
        if (rxActionMap[tag] != null && !rxActionMap[tag]!!.isDisposed) {
            rxActionMap[tag]!!.dispose()
            rxActionMap.remove(tag)
        }
    }

    fun <T : RxViewDispatch> unsubscribeRxView(`object`: T) {
        val tag = `object`.getRxTag()
        if (rxStoreMap[tag] != null && !rxStoreMap[tag]!!.isDisposed) {
            rxStoreMap[tag]!!.dispose()
            rxStoreMap.remove(tag)
        }
    }

    fun postRxAction(action: RxAction) {
        bus.send(action)
    }

    fun postRxStoreChange(storeChange: RxStoreChange) {
        bus.send(storeChange)
    }
}